import pyglet,sys,os,math,time
from pyglet.gl import *
from framework import *
from widget import *
from resize import *
from modeview import STFViewMode,ZoomViewMode,PixelViewMode
from pyglet.window import key,mouse

from Tkinter import *
import tkMessageBox
import tkFileDialog

from PIL import Image,ImageOps
Image.init()


class EditControl(icuControl):

    def on_mouse_press(self,x,y,button,modifiers):
        if button == mouse.LEFT:
            if not self.mode.hitEnter(x,y): self.mode.close()
        return False

    def on_mouse_drag(self,x,y,dx,dy,button,modifiers):
        if button == mouse.LEFT:
            self.mode.hitDrag(x,y,dx,dy)
        return False

    def on_mouse_release(self,x,y,button,modifiers):
        if button == mouse.LEFT:
            self.mode.hitExit(x,y)
        return False

    def on_resize(self,width,height):
        self.mode.view.recalc = True
        return False


class EditView(icuView):

    TRANSPARENCYMASK = (GLubyte * 128)(0x00,0x60,0x00,0x00,
                                       0x00,0x70,0x00,0x00,
                                       0x00,0x78,0x00,0x00,
                                       0x00,0x7C,0x00,0x00,
                                       0x00,0x7E,0x00,0x00,
                                       0x00,0x7F,0x00,0x00,
                                       0x00,0x7F,0x80,0x00,
                                       0x00,0x7F,0xC0,0x00,
                                       0x00,0x7F,0xE0,0x00,
                                       0x00,0x78,0xF0,0x00,
                                       0x00,0x70,0x70,0x00,
                                       0x00,0x70,0x38,0x00,
                                       0x00,0x70,0x38,0x00,
                                       0x00,0x70,0x1C,0x00,
                                       0x00,0x70,0x1C,0x00,
                                       0x00,0x38,0x0E,0x00,
                                       0x00,0x38,0x0E,0x00,
                                       0x00,0x1C,0x07,0x00,
                                       0x00,0x1C,0x07,0x00,
                                       0x00,0x0E,0x1F,0x80,
                                       0x00,0x0E,0x7F,0x80,
                                       0x00,0x07,0xF9,0xC0,
                                       0x00,0x07,0xE1,0xC0,
                                       0x00,0x03,0x80,0xE0,
                                       0x00,0x03,0x80,0xE0,
                                       0x00,0x01,0xC3,0xE0,
                                       0x00,0x01,0xCF,0xC0,
                                       0x00,0x00,0xFF,0x80,
                                       0x00,0x00,0xFE,0x00,
                                       0x00,0x00,0x70,0x00,
                                       0x00,0x00,0x00,0x00)

    def __init__(self,mode):
        self.closinganim = False
        self.mode = mode
        self.sprite = []
        self.rootnode = None
        self.image = None
        self.recalc = True
        glClearColor(1.0,1.0,1.0,1.0) #238/255.,242/255.,251/255.,1.0)
        self.ttwid = None

    def update(self,dt):
        for spr in self.sprite: spr.update(dt)
        if self.rootnode: self.rootnode.update(dt)
        if self.closinganim and not self.rootnode.sanim.active():
            for spr in self.sprite: spr.delete()
            self.rootnode.deletehierarchy()
            self.mode.destroy()
            main.mode.pop()
            main.mode.append(self.mode.backobj())
        ttwid = self.rootnode.gethitobj(*main.mpos)
        if ttwid and ttwid == self.ttwid:
            main.tooltip.create(dt,ttwid,*main.mpos)
        else:
            main.tooltip.kill(dt)
            self.ttwid = ttwid

    def draw(self):
        w,h = main.winman.window.get_size()
        glEnable(GL_POLYGON_STIPPLE)
        glPolygonStipple(self.__class__.TRANSPARENCYMASK)
        glColor4ub(204,204,204,255)
        glRectf(0,0,w,h)
        glDisable(GL_POLYGON_STIPPLE)
        if self.recalc: self.recalcpos()
        self.recalc = False
        self.image.draw()
        for spr in self.sprite: spr.draw()
        if self.rootnode: self.rootnode.draw()

    def recalcpos(self): #recenter and scale
        w,h = main.winman.window.get_size()
        self.image.scale = 1.0 #to fix image's width/height values (make them actual pixel values)
        self.image.scale = min(w/float(self.image.width),h/float(self.image.height))
        #print self.image.rotation % 360
        self.image.x = w//2#(w + ((self.mode.currot%360) > 135 and 1 or -1)*self.image.width)/2 #- self.image.width)/2
        self.image.y = h//2#(h + (45 < (self.mode.currot%360) < 225 and 1 or -1)*self.image.height)/2 #- self.image.height)/2
        self.rootnode.sanim.ax.offset = w//2; self.rootnode.sanim.ay.offset = h//2
        self.rootnode.update(0,True)


class EditMode(icuMode):

    images = None

    def __init__(self,opener):
        self.control = EditControl(self)
        self.view = EditView(self)
        self.img = main.loadImage(main.piclist[main.curIndex]) #reloading seems to be the only way to get anchor pts to work...
        self.img.anchor_x = self.img.width//2
        self.img.anchor_y = self.img.height//2
        self.view.image = pyglet.sprite.Sprite(self.img)
        self.unsaved = False
        self.closinganim = False
        self.backobj = opener
        w,h = main.winman.window.get_size()
        if self.__class__.images == None: #self.__class__.images is more formal, and I like to use it when caching images
            self.__class__.images = [pyglet.image.load("Edit_Rotate.png"), #Rotate (red)
                                     pyglet.image.load("Edit_FlipH.png"), #FlipH (yellow)
                                     pyglet.image.load("Edit_FlipV.png"), #FlipV (purple)
                                     pyglet.image.load("Edit_Resize.png"), #Resize (green)
                                     pyglet.image.load("Edit_Save.png"), #Save (teal)
                                     pyglet.image.load("Edit_Back.png"), #Exit (dark blue)
                                     pyglet.image.load("EditMode.png")] #Edit Mode (for center)
            for img in self.__class__.images: #center the anchor point (defaults to BL corner)
                img.anchor_x = img.width/2
                img.anchor_y = img.height/2

        angleamt = 360/6.
        centerspr = pyglet.sprite.Sprite(self.images[6],w//2,h//2)
        centerspr.opacity = 0
        centerspr.scale = 80/50.
        centerspr.color = (128,128,128)
        widroot = EditWidget(centerspr,40,"Edit mode",69)
        widroot.sanim.fadein([0.5]) #smoothly fade in center in half a second

        fcnlist = [["Rotate (drag)",93,self.rotateImage],
                   ["Flip horizontal",97,self.flip,[True,False]],
                   ["Flip vertical",81,self.flip,[False,True]],
                   ["Resize",47,self.resizeAndSave],
                   ["Save As...",69,self.applyAndSave],
                   ["Back",35,self.close]]
        for i in xrange(0,6):
            newsprite = pyglet.sprite.Sprite(self.images[i])
            newsprite.opacity = 0
            fcn = self.defaultfcn
            newwid = widroot.attach((i and FuncWidget or RotateWidget)(newsprite,25,*fcnlist[i]),angleamt*i,0)
            newwid.sanim.fadein([0.3],[],[0.2])
            newwid.length.add([0.5],80,2)

        self.view.rootnode = widroot

        self.curhflip = False
        self.curvflip = False
        self.currot = 0

    def upperlayer(self): return False

    def destroy(self): #clean up sprite memory
        self.view.image.delete()

    def defaultfcn(self,callingwidget):
        print "Clicked",callingwidget
        self.close()
        callingwidget.length.cut()
        callingwidget.length.add([0.3],-40,2)

    def hitEnter(self,x,y): return self.view.rootnode.hitenter(x,y)

    def hitExit(self,x,y): return self.view.rootnode.hitexit(x,y)

    def hitDrag(self,x,y,dx,dy):
        w,h = main.winman.window.get_size()
        sx = self.view.rootnode.sprite.x; sy = self.view.rootnode.sprite.y
        pushamt = 105 #pixels
        if sx+dx < pushamt: dx = pushamt-sx
        elif sx+dx > w-pushamt: dx = w-pushamt-sx
        if sy+dy < pushamt: dy = pushamt-sy
        elif sy+dy > h-pushamt: dy = h-pushamt-sy
        return self.view.rootnode.hitdrag(x,y,dx,dy)

    def close(self,wcall=None):
        if not self.unsaved or tkMessageBox.askyesno("Leave edit without saving?",
                                                     "Do you want to exit edit mode\nwithout saving changes?",
                                                     default=tkMessageBox.NO,icon=tkMessageBox.QUESTION):
            widroot = self.view.rootnode
            widroot.sanim.fadeout([0.3])
            for wid in widroot.child:
                wid.sanim.fadeout([0.3])
                wid.length.add([0.3],40,2)
            if wcall:
                wcall.length.cut()
                wcall.length.add([0.3],-40,2)
            self.view.closinganim = True
            main.tooltip.kill(1.0)
        main.winman.window.activate()

    def rotateImage(self,amt):
        self.currot -= amt
        self.view.image._set_texture(self.img.get_texture().get_transform(self.curhflip,self.curvflip,self.currot))
        self.view.recalc = True
        if not self.unsaved: main.winman.window.set_caption("* "+main.winman.window.caption)
        self.unsaved = True

    def flip(self,wcall,horiz,vert):
        if not wcall.sanim.active():
            if ((self.currot+45)//90)%2:
                temp = horiz
                horiz = vert
                vert = temp
            if horiz or vert:
                if horiz: self.curhflip = not self.curhflip
                if vert: self.curvflip = not self.curvflip
                self.view.image._set_texture(self.img.get_texture().get_transform(self.curhflip,self.curvflip,self.currot))
            wcall.length.add([0.15],20,3,[True])
            self.view.recalc = True
            if not self.unsaved: main.winman.window.set_caption("* "+main.winman.window.caption)
            self.unsaved = True

    def applyAndSave(self,wcall):
        oldfname = main.piclist[main.curIndex]
        newfname = tkFileDialog.asksaveasfilename(filetypes=main.tkfiletypelist,initialdir=main.curdir,initialfile=oldfname)
        if newfname:
            if self.unsaved: main.winman.window.set_caption(main.winman.window.caption[2:])
            self.unsaved = False
            hf = self.curhflip; vf = self.curvflip; rd = (360-self.currot) % 360
            if hf and vf:
                hf = vf = False
                rd = (rd+180)%360
            elif 179 < rd < 181 and (hf or vf):
                hf = vf; vf = self.curhflip
                rd = 0

            pic = Image.open(oldfname)
            if hf: pic = ImageOps.mirror(pic)
            if vf: pic = ImageOps.flip(pic)
            if rd < -1 or rd > 1: pic = pic.rotate(rd)
            pic.save(newfname)
        main.winman.window.activate()

    def resizeAndSave(self,wcall):
        resize = ResizeDialog(self.img.width,self.img.height)
        if resize.result:
            neww,newh,blend = resize.result
            oldfname = main.piclist[main.curIndex]
            newfname = tkFileDialog.asksaveasfilename(filetypes=main.tkfiletypelist,initialdir=main.curdir,initialfile=oldfname)
            if newfname:
                if self.unsaved: main.winman.window.set_caption(main.winman.window.caption[2:])
                self.unsaved = False
                hf = self.curhflip; vf = self.curvflip; rd = (360-self.currot) % 360
                if hf and vf:
                    hf = vf = False
                    rd = (rd+180)%360
                elif 179 < rd < 181 and (hf or vf):
                    hf = vf; vf = self.curhflip
                    rd = 0

                pic = Image.open(oldfname)
                if hf: pic = ImageOps.mirror(pic)
                if vf: pic = ImageOps.flip(pic)
                if rd < -1 or rd > 1: pic = pic.rotate(rd)
                if blend:
                    if neww > self.img.width or newh > self.img.height:
                        pic = pic.resize((neww,newh),Image.BICUBIC)
                    else: pic = pic.resize((neww,newh),Image.ANTIALIAS)
                else: pic = pic.resize((neww,newh))
                pic.save(newfname)
        main.winman.window.activate()

